import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:ichinesereader/constants.dart';
import 'package:ichinesereader/controller/cache.dart';
import 'package:ichinesereader/exam/dto/assessment.response.dart';
import 'package:ichinesereader/exam/util/ExamUtil.dart';
import 'package:ichinesereader/exam/widgets/BGExamRecorder.dart';
import 'package:ichinesereader/exam/widgets/BGExamTypeOption.dart';
import 'package:ichinesereader/widgets/tools/pdfviewer.dart';
import 'BGDashedRectWidget.dart';
import 'BGExamTypeChoice.dart';
import 'BGExamTypeMatch.dart';
import 'BGExamTypeSpeech.dart';
import 'BGExamTypeVanish.dart';
import 'BGSinglePlayer.dart';
import 'SampleAudioPlayer.dart';

///     ****************** BGExamWidget使用说明v1.0  ******************
/*
    1. 必传字段
      1> questionItem
      2> mode
          Review 用于浏览题（比如老师浏览，显示题内容及正确答案）；
          Practice 用于学生练习模式
          Test 用于学生测试模式
          Grade 用于老师评卷模式
          Graded用于老师评卷后的模式，如学生最后查看

    2. 可选字段
      1> getAnswer 获取返回结果（String或 map.toString()）
      2> isShowJudge
        是否显示评判结果  (一般用于字卡题，立即显示评判结果)
        choice字形选择题，默认值：true
        option选择题，   默认值：false
      3> isRecordSmall
         录音控件是否排列更紧凑 默认值为false
          running record中要求紧凑排列

    3. 字卡专属类 无mode
    <A> vanish 消消乐    存入item.answer 会在全部消除以后返回每个字卡首次消除记录；

    <B> choice 字形选择题 存入item.answer isShowJudge 默认为true，立即显示评判结果

    4. 通用类
    <C> match 连线题
      存入item.answer

    <D> option 选择题
      存入item.answer isShowJudge 默认为false，如需显示评判结果传true

    <E> write 写作题
      Practice & Test 存入item.answer
      Grade Graded 可选字段 totalScore 默认为10
      Grade打分结果存入 老师评语comment(可不填)  老师打分score(可不选) 默认为0分
      Graded需传入comment和score

    <F> speak 录音题
      Practice & Test
       删除 1> 点击录音结束按钮 返回音频文件本地地址localPath 存入item.answer
       删除 2> 点击保存按钮 返回fileId 存入item.answer
       删除 3> 点击删除按钮 返回"delete:" item.answer = ['']
       删除 4> 可根据后缀.m4a区分fileId和localPath，若未返回fileId可提示保存录音文件
      Grade Graded 可选字段 totalScore 默认为10
      Grade打分结果存入 老师评语comment(可不填)  老师打分score(可不选) 默认为0分
      Graded需传入comment和score

    <G> speech 跟读题
      fileId存入item.answer，AI评分intelligenceScore存入item.intelligenceScore
*/

///     ****************** mode  ******************
///     Review 用于浏览题（比如老师浏览，显示题内容及正确答案）；
///     Practice 用于学生练习模式
///     Test 用于学生测试模式
///     Grade 用于老师评卷模式
///     Graded用于老师评卷后的模式，如学生最后查看
enum BGExamWidgetMode { Review, Practice, Test, Grade, Graded }

class BGExamWidget extends StatefulWidget {
  BGExamWidget({
    Key? key,
    required this.questionItem,
    this.getAnswer,
    this.isShowJudge,
    this.isRecordSmall,
    this.questionId,
    this.mode = BGExamWidgetMode.Practice,
    this.switchSave,
    this.speakActionNum = 0,
  }) : super(key: key);
  final QuestionItem questionItem;
  final BGExamWidgetMode mode;
  final String? questionId;
  final int speakActionNum;

  /// 可选配置字段
  final Function(String)? getAnswer;

  // 是否显示评判结果  (一般用于字卡题，直接显示答案是否正确)
  // choice字形选择题，默认值：true
  // option选择题，   默认值：false
  final bool? isShowJudge;
  // 录音控件是否排列更紧凑
  final bool? isRecordSmall;
  final bool? switchSave;

  @override
  State<BGExamWidget> createState() => _BGExamWidgetState();
}

class _BGExamWidgetState extends State<BGExamWidget> {
  @override
  void dispose() {
    BGSinglePlayer().stop();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Widget option = SizedBox();
    String type = widget.questionItem.type ?? "option";
    if (type == "match" || type == "group") {
      // 连线题
      option = _buildQuestionMatch(widget.questionItem, widget.mode, context);
    } else if (type == "vanish") {
      // 消消乐 (字卡专属，无mode，无head)
      option = _buildQuestionVanish(widget.questionItem, widget.mode, context);
    } else if (type == "option" || type == "judge") {
      // 选择题
      option = _buildQuestionOption(widget.questionItem, widget.mode, context);
    } else if (type == "choice") {
      // 字形选择题 (字卡专属，无mode，无head)
      option = _buildQuestionChoice(widget.questionItem, widget.mode, context);
    } else if (type == "write") {
      // 写作题
      option = _buildQuestionWrite(widget.questionItem, widget.mode, context);
    } else if (type == "speak") {
      // 录音题
      option = _buildQuestionSpeak(widget.questionItem, widget.mode, context);
    } else if (type == "speech") {
      // 跟读题
      option = _buildQuestionSpeech(widget.questionItem, widget.mode, context);
    }else if (type == "sort") {
      // 排序题
      // option = _buildQuestionSpeech(widget.questionItem, widget.mode, context);
    }else if (type == "input" || type == "fill") {
      // 填空题
      // option = _buildQuestionSpeech(widget.questionItem, widget.mode, context);
    }
    return option;
  }

  ///     ****************** speech 跟读题 ******************
  Container _buildQuestionSpeech(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    bool isEditable =
        (mode == BGExamWidgetMode.Practice) || (mode == BGExamWidgetMode.Test);
    if (isEditable) {
      return Container(
          child: BGExamTypeSpeech(
              item: item,
              questionId: widget.questionId,
              getFileIdAndAIScore: (String fileId, int intelligenceScore) {
                item.answer = [fileId];
                item.intelligenceScore = intelligenceScore;
                if (widget.getAnswer != null) {
                  var map = {
                    'fileId': fileId,
                    'intelligenceScore': intelligenceScore
                  };
                  widget.getAnswer!(map.toString());
                }
              }));
    }

    List<Widget> options = [];
    options.add(_buildHeadWidget(item.head, context));
    if (item.answer == null || item.answer!.isEmpty) {
      if (mode == BGExamWidgetMode.Grade || mode == BGExamWidgetMode.Graded) {
        options.add(SizedBox(height: 10));
        options.add(Text('No Recording Submitted.'.tr,
            style: TextStyle(
                fontFamily: 'Noto Sans SC',
                fontSize: 21,
                fontWeight: FontWeight.w700)));
        options.add(SizedBox(height: 15));
      }
    } else {
      options.add(Row(
        children: [
          Text('AI Score: '.tr,
              style: TextStyle(
                  fontFamily: 'Noto Sans SC',
                  fontSize: 22,
                  fontWeight: FontWeight.w700)),
          Text(item.intelligenceScore.toString(),
              style: TextStyle(
                  fontFamily: 'Noto Sans SC',
                  fontSize: 22,
                  fontWeight: FontWeight.w700,
                  color: Colors.red))
        ],
      ));
      options.add(SizedBox(height: 10));
      options.add(
        Text('Student Recording: '.tr,
            style: TextStyle(
              fontFamily: 'Noto Sans SC',
              fontSize: 21,
            )),
      );
      options.add(SizedBox(height: 10));
      options.add(SampleAudioPlayer(
          name: 'audioPlayerEvaluation',
          audioUrl: '',
          audioId: item.answer![0]));
      options.add(SizedBox(height: 15));
    }
//AI 跟读测试题框
    return Container(
        color: Colors.transparent,
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.start, children: options));
  }

  ///     ****************** speak 录音题 ******************
  /* BGRecorder 使用说明
    *  @required  getFileId        保存成功后获取fileId
    *  @option    audioUrl         player的播放地址,支持url、localPath、fileId
    *             getLocalPath     获取录音本地存储路径
    *             getDeleteAction  获取删除事件
    *
    *             可根据后缀.m4a区分fileId和localPath
    *             如果fileId为空，翻页的时候可以提示保存录音文件
    * */

  Container _buildQuestionSpeak(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    List<Widget> options = [];
    String recordUrl = '';
    if (item.answer != null && item.answer!.isNotEmpty) {
      recordUrl = item.answer![0];
    }
    bool isEditable =
        (mode == BGExamWidgetMode.Practice) || (mode == BGExamWidgetMode.Test);

    options.add(_buildHeadWidget(item.head, context));

    if (isEditable) {
      bool isTest = false;
      if (item.head?.json != null && item.head!.json!.contains('%isTest%')) {
        isTest = true;
      }
      options.add(SizedBox(height: 20));
      options.add(BGExamRecorder(
          fileId: recordUrl,
          isRecordSmall: widget.isRecordSmall ?? false,
          isTest: isTest,
          actionNum: widget.speakActionNum,
          getFileId: (fileId) {
            item.answer = [fileId];
            if (widget.getAnswer != null) {
              widget.getAnswer!(fileId);
            }
          }));
    } else if (mode == BGExamWidgetMode.Review) {
      final box = Hive.box('appconfig');
      bool isStudent = box.get(CacheManagerKey['nanhairole'].toString()) ==
          Constants.NanhaiRole_Student;
      if (isStudent) {
        options.add(SizedBox(height: 20));
        if (recordUrl.isEmpty) {
          options.add(Text('No Recording Submitted.'.tr,
              style: TextStyle(
                  fontFamily: 'Noto Sans SC',
                  fontSize: 21,
                  fontWeight: FontWeight.w700)));
        } else {
          options.add(SampleAudioPlayer(
              name: 'audioPlayerEvaluation', audioUrl: '', audioId: recordUrl));
        }
      }
    } else {
      options.add(SizedBox(height: 10));
      if (recordUrl.isEmpty) {
        options.add(Text('No Recording Submitted.'.tr,
            style: TextStyle(
                fontFamily: 'Noto Sans SC',
                fontSize: 21,
                fontWeight: FontWeight.w700)));
      } else {
        options.add(SampleAudioPlayer(
            name: 'audioPlayerEvaluation', audioUrl: '', audioId: recordUrl));
      }
      options.add(SizedBox(height: 10));
      options.add(buildScoreWidget(
          item, mode == BGExamWidgetMode.Grade, false, context));
    }
    if (mode == BGExamWidgetMode.Practice || mode == BGExamWidgetMode.Review) {
      RxBool isShowReference = false.obs;
      String show = '';
      if (item.reference != null && item.reference!.show != null) {
        show = item.reference!.show ?? '';
      }
      if (show.isNotEmpty) {
        options.add(SizedBox(height: 15));
        options.add(SizedBox(
            width: 180,
            child: MaterialButton(
                child: Row(children: [Icon(Icons.keyboard_arrow_down, size: 20), SizedBox(width: 2), Text('Reference Answer'.tr)]),
                color: Theme.of(Get.context!).colorScheme.secondary,
                onPressed: () {
                  isShowReference.value = !isShowReference.value;
                })));
        options.add(SizedBox(height: 15));
      }
      options.add(Obx(() {
        return Visibility(
            visible: isShowReference.value,
            child: BGDashedRectWidget(child: Container(margin: EdgeInsets.all(20), child: ExamUtil.buildHeadInfoWidget(item.reference, context))));
      }));

      options.add(SizedBox(height: 160));
    }
    return Container(
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.start, children: options));
  }

  ///     ****************** write 写作题 ******************
  Container _buildQuestionWrite(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    /*
    * 分两个模块  write输入框   打分+评语
    * write输入框 两种状态  isEditable可输入，否则readOnly
    * 打分+评语   两种状态   Grade可选择，Graded仅展示
    * */
    List<Widget> options = [];
    bool isEditable =
        (mode == BGExamWidgetMode.Practice) || (mode == BGExamWidgetMode.Test);
    // overwrite isEditable for switching from edit to save
    if (widget.switchSave != null && widget.switchSave == false) {
      isEditable = false;
    }

    options.add(_buildHeadWidget(item.head, context));
    options.add(SizedBox(height: 10));
    options.add(SizedBox(
        height: 200,
        child: TextField(
          controller: _writeController(item, isEditable),
          readOnly: !isEditable,
          maxLines: 100,
          minLines: 15,
          decoration: InputDecoration(
              border:
                  OutlineInputBorder(borderRadius: BorderRadius.circular(5)),
              hintText: 'Writing your answer！'.tr,
              hintStyle: TextStyle(fontFamily: 'Noto Sans SC')),
        )));
    if (mode == BGExamWidgetMode.Grade || mode == BGExamWidgetMode.Graded) {
      options.add(SizedBox(height: 10));
      options.add(buildScoreWidget(
          item, mode == BGExamWidgetMode.Grade, true, context));
    }
    if (mode == BGExamWidgetMode.Practice || mode == BGExamWidgetMode.Review) {
      RxBool isShowReference = false.obs;
      String show = '';
      if (item.reference != null && item.reference!.show != null) {
        show = item.reference!.show ?? '';
      }
      if (show.isNotEmpty) {
        options.add(SizedBox(height: 15));
        options.add(SizedBox(
            width: 180,
            child: MaterialButton(
                child: Row(children: [Icon(Icons.keyboard_arrow_down, size: 20), SizedBox(width: 2), Text('Reference Answer'.tr)]),
                color: Theme.of(Get.context!).colorScheme.secondary,
                onPressed: () {
                  isShowReference.value = !isShowReference.value;
                })));
        options.add(SizedBox(height: 15));
      }
      options.add(Obx(() {
        return Visibility(
            visible: isShowReference.value,
            child: BGDashedRectWidget(child: Container(margin: EdgeInsets.all(20), child: ExamUtil.buildHeadInfoWidget(item.reference, context))));
      }));

      options.add(SizedBox(height: 160));
    }
    return Container(
        child: TapRegion(
            onTapOutside: (_) => FocusScope.of(Get.context!).requestFocus(new FocusNode()),
            child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: options)));
  }

  TextEditingController _writeController(
      QuestionItem questionItem, bool isEditable) {
    List<String>? answer = questionItem.answer;
    String writeText = '';
    if (answer != null && answer.isNotEmpty) {
      writeText = answer[0];
    }
    //
    if (!isEditable && writeText.isEmpty) {
      writeText = 'No content';
    }
    TextEditingController writeController =
        TextEditingController(text: writeText);
    if (isEditable) {
      writeController.addListener(() {
        if(writeController.text.isNotEmpty){
          questionItem.answer = [writeController.text];
          if (widget.getAnswer != null) {
            widget.getAnswer!(writeController.text);
          }
        }else{
          questionItem.answer = null;
        }
      });
    }
    return writeController;
  }

  Widget buildScoreWidget(
      QuestionItem item, bool isEditable, bool isWrite, BuildContext context) {
    if (item.totalScore == null || item.totalScore! < 1) {
      item.totalScore = 10;
    }

    List<Widget> optionsList = [];
    final box = Hive.box('appconfig');
    RxInt radioGroupValue = 0.obs;

    radioGroupValue.value = item.score ?? 0;

    int num = item.totalScore! + 1;

    for (int i = 1; i < num; i++) {
      optionsList.add(SizedBox(
          width: 70,
          child: Obx(() => Row(children: [
                Radio<int>(
                    value: i,
                    activeColor: Colors.blue,
                    groupValue: radioGroupValue.value,
                    onChanged: (value) {
                      if (isEditable) {
                        radioGroupValue.value = i;
                        item.score = i;
                        if (widget.getAnswer != null) {
                          var map = {
                            'comment': item.comment ?? '',
                            'score': item.score ?? 0
                          };
                          widget.getAnswer!(map.toString());
                        }
                      }
                    }),
                Text(i.toString(),
                    style: TextStyle(
                        fontFamily: 'Noto Sans SC',
                        fontSize: 18,
                        height: 1.8,
                        color: i == radioGroupValue.value
                            ? Colors.blue
                            : (Get.isDarkMode
                                ? Color(0xFF757575)
                                : Colors.black87),
                        fontWeight: FontWeight.w500)),
              ]))));
    }

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        SizedBox(height: 15),
        SizedBox(
          width: MediaQuery.of(context).size.width - 80,
          child: Wrap(spacing: 20, children: optionsList),
        ),
        SizedBox(height: 15),
        Container(
            alignment: Alignment.centerLeft,
            child: Row(
              children: [
                Text('Comment',
                    style: TextStyle(
                        fontFamily: 'Noto Sans SC',
                        fontSize: 18,
                        height: 1.8,
                        color: (Get.isDarkMode
                            ? Color(0xFF757575)
                            : Colors.black87),
                        fontWeight: FontWeight.w600)),
                SizedBox(width: 5),
                IconButton(
                    onPressed: () async {
                      int ql = box.get('evaluationRecordLevel') ?? 1;
                      String pdfAddress = '';
                      if (isWrite) {
                        pdfAddress = 'assets/docs/wL1-L8.pdf';
                        if (ql > 8) pdfAddress = 'assets/docs/wL9-L17.pdf';
                      } else {
                        pdfAddress = 'assets/docs/sL1-L8.pdf';
                        if (ql > 8) pdfAddress = 'assets/docs/sL9-L17.pdf';
                      }
                      Get.to(() => PDFViewer(pdfaddress: pdfAddress));
                    },
                    icon: Icon(Icons.info)),
              ],
            )),
        SizedBox(height: 5),
        SizedBox(
            height: 200,
            child: TextField(
                controller: TextEditingController(
                    text: isEditable
                        ? item.comment
                        : (item.comment ?? 'No comment')),
                readOnly: !isEditable,
                maxLines: 100,
                minLines: 15,
                onChanged: (text) {
                  item.comment = text;
                  if (widget.getAnswer != null) {
                    var map = {
                      'comment': item.comment ?? '',
                      'score': item.score ?? 0
                    };
                    widget.getAnswer!(map.toString());
                  }
                },
                decoration: InputDecoration(
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(5)),
                    hintText: isEditable ? 'Writing your Comment' : '')))
      ],
    );
  }

  ///     ****************** choice 字形选择题 ******************
  BGExamTypeChoice _buildQuestionChoice(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    return BGExamTypeChoice(
        item: item,
        isShowJudge: widget.isShowJudge ?? true,
        getAnswer: (answerStr) {
          item.answer = [answerStr];
          if (widget.getAnswer != null) {
            widget.getAnswer!(answerStr);
          }
        });
  }

  ///     ****************** option 选择题 ******************
  Container _buildQuestionOption(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    List<Widget> options = [];
    List<String>? answer = item.answer;
    RxString selectValue = ''.obs;
    options.add(SizedBox(height: 5));
    options.add(_buildHeadWidget(item.head, context));
    options.add(SizedBox(height: 15));
    if (answer != null && answer.isNotEmpty) {
      selectValue.value = answer[0];
    }

    if (item.body != null) {
      options.add(
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Obx(() {
              return BGExamTypeOption(
                  item: item,
                  value: selectValue.value,
                  mode: mode,
                  isShowJudge: widget.isShowJudge ?? false,
                  onChanged: (value) {
                    item.answer = [value];
                    if (widget.getAnswer != null) {
                      widget.getAnswer!(value);
                    }
                    selectValue.value = value;
                  });
            }),
            SizedBox(height: 40)
          ],
        ),
      );
    }

    return Container(
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.start,
            children: options));
  }

  ///     ****************** vanish 消消乐 ******************
  BGExamTypeVanish _buildQuestionVanish(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    return BGExamTypeVanish(
        item: item,
        getAnswer: (record) {
          item.answer = [record];
          if (widget.getAnswer != null) {
            widget.getAnswer!(record);
          }
        });
  }

  ///     ****************** match 连线题 ******************
  Container _buildQuestionMatch(
      QuestionItem item, BGExamWidgetMode mode, BuildContext context) {
    List<Widget> options = [];
    options.add(SizedBox(height: 5));
    options.add(_buildHeadWidget(item.head, context));
    options.add(SizedBox(height: 15));
    options.add(BGExamTypeMatch(
        item: item,
        mode: mode,
        getAnswer: (answer) {
          item.answer = answer;
          if (widget.getAnswer != null) {
            widget.getAnswer!(answer.toString());
          }
        }));
    return Container(
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.start,
            children: options));
  }

  Widget _buildHeadWidget(QuestionContent? element, BuildContext context){
    if (element != null && element.json != null && element.json!.contains('%hidden%')) return SizedBox();
    return ExamUtil.buildHeadInfoWidget(element, context);
  }
}
